<template>
  <view class="data-tree">
    <scroll-view class="data-tree-scroll" :scroll-y="true" :scroll-x="false">
      <view
        class="data-tree-item"
        v-for="(item, index) in treeData"
        :key="item.key !== undefined ? item.key : index"
      >
        <view
          class="data-tree-item__indent"
          :style="{ width: calcIndent(item.level) }"
        ></view>
        <view
          v-if="showCheckbox"
          class="data-tree-item__checkbox"
          :class="{
            multiple: multiple,
          }"
          @click="(e) => handleStatus(item, e)"
        >
          <view class="data-tree-item__checkbox-outline" :class="item.status">
            <view
              v-if="multiple && item.status === 'checked'"
              class="dot iconfont icon-xuanzhong"
            ></view>
            <view v-else class="dot"></view>
          </view>
        </view>
        <view
          class="data-tree-item__label"
          :class="{
            'is-active': item.status === 'checked',
            'is-expanded': item.expanded,
          }"
          @click="item.active = !item.active"
        >
          {{ item.label }}父级:{{ item.parent }}
        </view>
      </view>
    </scroll-view>
  </view>
</template>
<script>
import { generateNodeList } from "./utils";
export default {
  props: {
    data: {
      type: Array,
      default: () => [],
    },
    labelField: {
      type: String,
      default: "label",
    },
    keyField: {
      type: String,
      default: "id",
    },
    indent: {
      type: [String, Number],
      default: "20px",
    },
    showCheckbox: {
      type: Boolean,
      default: false,
    },
    multiple: {
      type: Boolean,
      default: false,
    },
    checkStrictly: {
      type: Boolean,
      default: false,
    },
  },
  data() {
    return {
      treeData: [], // 树形数据
      checkedNodes: [], // 已选节点列表
      halfCheckedNodes: [], // 半选节点列表
      checkedNodeKeys: [], // 已选节点keys
      halfCheckedNodeKeys: [], // 半选选节点ids
    };
  },
  computed: {},
  watch: {
    data: {
      handler(val) {
        console.log("🚀 ~ handler ~ val:", val);
        this.treeData = generateNodeList(val, this.$props);
      },
      immediate: true,
    },
  },
  methods: {
    /**
     * 计算缩进
     * @param level
     */
    calcIndent(level) {
      let width = 0;
      if (typeof this.indent === "number") {
        width = `${level * this.indent}px`;
      } else if (typeof this.indent === "string") {
        const numberMatch = this.indent.match(/^[0-9]+/);
        if (numberMatch) {
          const num = parseInt(numberMatch[0]);
          const unit = this.indent.substring(numberMatch[0].length);
          width = `${level * num}${unit}`;
        } else {
          console.error(
            'indent属性传入一个字符串时，必须是一个合法的数字+像素单位，如："20px"'
          );
          width = `${level * 20}px`;
        }
      }
      console.log("🚀 ~ calcIndent ~ width:", width);
      return width;
    },
    /**
     * 处理节点选中事件
     * @param node
     * @param e
     */
    handleStatus(node, e) {
      // 首先切换节点选中状态

      node.status = node.status === "checked" ? "none" : "checked";
      console.log(
        "🚀 ~ handleStatus ~ node.status:",
        node.status === "checked"
      );
      // 单选
      if (!this.multiple) {
        this.treeData.forEach((item) => {
          if (item.key !== node.key) {
            item.status = "none";
          }
        });
        // 如果父子关联
        if (!this.checkStrictly) {
          this.setHalf(node);
        }
      } else {
        // 如果父子关联
        if (!this.checkStrictly) {
          this.setHalf(node);
          const children = this.findAllChildren(node);
          children.forEach(
            (ch) => (ch.status = node.status === "checked" ? "checked" : "none")
          );
        }
      }
    },
    /**
     * 设置半选状态
     */
    setHalf(node) {
      const parentNodes = this.findAllParents(node);
      parentNodes.forEach((parentNode) => {
        parentNode.status = "half";
      });
    },
    /**
     * 查询所有父级节点
     * @param node
     */
    findAllParents(node) {
      const parentNodes = [];
      let parentKey = node.parent;
      while (parentKey && parentKey !== "ROOT_NODE") {
        const parentNode = this.treeData.find((el) => el.key === parentKey);
        parentNodes.push(parentNode);
        parentKey = parentNode.parent;
      }
      return parentNodes;
    },
    findAllChildren(node) {
      const children = [];
      const stack = [node];
      while (stack.length) {
        const current = stack.shift();
        const currentChildren = this.treeData.filter(
          (el) => el.parent === current.key
        );
        children.push(...currentChildren);
        if (currentChildren.length) {
          stack.push(...currentChildren);
        }
      }
      return children;
    },
  },
};
</script>
<style lang="scss">
.data-tree {
  width: 100%;
  height: 100%;
  padding: 12px;
  box-sizing: border-box;
  .data-tree-scroll {
    width: 100%;
    height: 100%;
  }
  .data-tree-item {
    display: flex;
    justify-content: flex-start;
    align-self: center;
    padding: 4px 0;
    .data-tree-item__checkbox {
      flex: none;
      width: 20px;
      height: 20px;
      margin-right: 4px;
      padding: 1px;
      box-sizing: border-box;
      display: flex;
      justify-content: center;
      align-items: center;
      padding: 1px;
      box-sizing: border-box;
      .data-tree-item__checkbox-outline {
        width: 100%;
        height: 100%;
        border: 2px solid #222222;
        border-radius: 50%;
        display: flex;
        justify-content: center;
        align-items: center;
        .dot {
          flex: auto;
          height: 100%;
        }
        &.none {
          box-sizing: border-box;
          .dot {
            display: none;
          }
        }
        &.half {
          padding: 4px;
          box-sizing: border-box;
          border-color: #4697ec;

          .dot {
            border-radius: 50%;
            background-color: #4697ec;
          }
        }
        &.checked {
          box-sizing: border-box;
          padding: 2px;
          border-color: #4697ec;
          .dot {
            border-radius: 50%;
            background-color: #4697ec;
          }
        }
      }
      &.multiple {
        .data-tree-item__checkbox-outline {
          border-radius: unset;
          padding: 1px;
          &.half {
            background-color: #4697ec;
            .dot {
              background-color: #fff;
              border-radius: unset;
              height: 2px;
            }
          }
          &.checked {
            background-color: #4697ec;
            .dot {
              border-radius: unset;
              color: #fff;
            }
          }
        }
      }
    }
    &__indent {
      flex: none;
    }
    &__label {
      flex: auto;
      &.is-active {
        color: #4697ec;
      }
    }
  }
}
</style>
